#include <stdlib.h>
#include <string.h>
#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/listener.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string>
#include <iostream>
#include <jsoncpp/json/json.h>
#include <cstring>
#include <mysql/mysql.h>

using namespace std;

const int LIS_MAX = 10;
enum OP_TYPE
{
    Enter = 1,
    Register,
    Check,
    Schedule,
    Mine,
    Cancel,
    Leave
};

// MySQL 客户端
class mysql_client
{
public:
    mysql_client(const string &ips = "127.0.0.1", const string &user = "root", const string &dbname = "project1", const string &passwd = "123qwe")
        : db_ips(ips), db_username(user), db_dbname(dbname), db_passwd(passwd)
    {
        mysql_init(&mysql_con);
    }

    ~mysql_client()
    {
        mysql_close(&mysql_con);
    }

    bool mysql_ConnectServer()
    {
        if (mysql_real_connect(&mysql_con, db_ips.c_str(), db_username.c_str(), db_passwd.c_str(), db_dbname.c_str(), 0, NULL, 0) == NULL)
        {
            cout << "MySQL connection failed: " << mysql_error(&mysql_con) << endl;
            return false;
        }
        return true;
    }

    bool mysql_Register(const string &tel, const string &passwd, const string &username)
    {
        string sql = "INSERT INTO user_info (tel, user_name, psswad, status) VALUES('" + tel + "','" + username + "','" + passwd + "', 1)";
        if (mysql_query(&mysql_con, sql.c_str()) != 0)
        {
            cout << "MySQL query failed: " << mysql_error(&mysql_con) << endl;
            return false;
        }
        return true;
    }

    bool mysql_Login(const string &tel, const string &passwd, string &name)
    {
        // select user_name,psswad from user_info where tel=13200000000;
        string sql1 = string("select user_name,psswad from user_info where tel=") + tel;
        if (mysql_query(&mysql_con, sql1.c_str()) != 0)
        {
            return false;
        }

        MYSQL_RES *res = mysql_store_result(&mysql_con);
        if (res == nullptr)
            return false;

        int num = mysql_num_rows(res);
        if (num == 0)
        {
            mysql_free_result(res);
            return false;
        }

        MYSQL_ROW row = mysql_fetch_row(res);

        string password = row[1];
        if (password.compare(passwd) != 0)
        {
            return false;
        }

        name = row[0];
        mysql_free_result(res);
        return true;
    }

    bool mysql_Show_ticket(Json::Value &resval)
    {
        string sql = "select tk_id,addr,max,num,use_date from ticket_info";
        if (mysql_query(&mysql_con, sql.c_str()) != 0)
        {
            cout << "show ticket error" << endl;
            return false;
        }
        MYSQL_RES *r = mysql_store_result(&mysql_con);
        if (r == nullptr)
            return false;
        int n = mysql_num_rows(r);

        resval["status"] = "OK";
        resval["count"] = n;

        for (int i = 0; i < n; i++)
        {
            MYSQL_ROW row = mysql_fetch_row(r);
            Json::Value tmp;
            tmp["tk_id"] = row[0];
            tmp["add"] = row[1];
            tmp["max"] = row[2];
            tmp["num"] = row[3];
            tmp["use_date"] = row[4];
            resval["info"].append(tmp);
        }
        mysql_free_result(r);
        return true;
    }

    bool mysql_Subscribe_ticket(int tk_id, string tel)
    {
        mysql_begin();
        string order = string("select max,num from ticket_info where tk_id = ") + to_string(tk_id);

        if (mysql_query(&mysql_con, order.c_str()) != 0)
        {
            cout << "查询max,num失败" << endl;
            mysql_rollback();
            return false;
        }

        MYSQL_RES *r = mysql_store_result(&mysql_con);
        if (r == NULL)
        {
            cout << "获取结果集失败" << endl;
            mysql_rollback();
            return false;
        }

        int Num = mysql_num_rows(r);
        if (Num != 1)
        {
            cout << "记录不为1" << endl;
            mysql_rollback();
            return false;
        }

        MYSQL_ROW row = mysql_fetch_row(r);
        string str_max = row[0]; // 总票数
        string str_num = row[1]; // 当前已定票数
        int tk_max = atoi(str_max.c_str());
        int tk_num = atoi(str_num.c_str());
        if (tk_max <= tk_num)
        {
            cout << "没有可用的票" << endl;
            mysql_rollback();
            return false;
        }

        tk_num++;
        string s = string("update ticket_info set num=") + to_string(tk_num) + string(" where tk_id=") + to_string(tk_id);
        if (mysql_query(&mysql_con, s.c_str()) != 0)
        {
            cout << "修改u预定票数失败" << endl;
            mysql_rollback();
            return false;
        }

        // insert into sub_tick values(0,1,'18900000000',now());
        string s2 = string("insert into sub_tick values(0,") + to_string(tk_id) + string(",'") + tel + string("',now())");
        if (mysql_query(&mysql_con, s2.c_str()) != 0)
        {
            cout << "存入预定信息失败" << endl;
            mysql_rollback();
            return false;
        }

        mysql_commit();
        return true;
    }

    bool mysql_User_Show(Json::Value &resval, string usertel)
    {
        string sql = "select * from sub_tick where tel='" + usertel + "'";
        if (mysql_query(&mysql_con, sql.c_str()) != 0)
        {
            cout << "sql执行语句失败" << endl;
            return false;
        }

        MYSQL_RES *r = mysql_store_result(&mysql_con);
        if (r == nullptr)
        {
            cout << "查询结果为空" << endl;
            return false;
        }

        MYSQL_ROW row = mysql_fetch_row(r);
        if (row == nullptr) // 如果没有数据返回
        {
            cout << "没有找到数据" << endl;
            mysql_free_result(r);
            return false;
        }

        resval["status"] = "OK";
        resval["yd_id"] = row[0];
        resval["tk_id"] = row[1];

        mysql_free_result(r);
        return true;
    }

    bool User_Cancel_ticket(int yd_id, int tk_id)
    {
        mysql_begin();
        string s1 = ("delete from sub_tick where yd_id=") + to_string(yd_id);
        if (mysql_query(&mysql_con, s1.c_str()) != 0)
        {
            cout << "sql1执行语句失败" << endl;
            mysql_rollback();
            return false;
        }

        string s2 = ("select num from ticket_info where tk_id=") + to_string(tk_id);
        if (mysql_query(&mysql_con, s2.c_str()) != 0)
        {
            cout << "sql2执行语句失败" << endl;
            mysql_rollback();
            return false;
        }

        MYSQL_RES *r = mysql_store_result(&mysql_con);
        if (r == nullptr)
        {
            cout << "查询结果为空" << endl;
            return false;
        }

        MYSQL_ROW j = mysql_fetch_row(r);
        if (j == nullptr)
        {
            cout << "未找到指定的票务记录" << endl;
            mysql_free_result(r);
            mysql_rollback();
            return false;
        }

        int current_num = atoi(j[0]);
        if (current_num > 0)
            current_num--;

        string s3 = ("update ticket_info set num=" )+ to_string(current_num) + (" where tk_id=" )+ to_string(tk_id);
        if (mysql_query(&mysql_con, s3.c_str()) != 0)
        {
            cout << "更新执行失败" << endl;
            mysql_free_result(r);
            mysql_rollback();
            return false;
        }

        // 提交事务
        mysql_commit();
        mysql_free_result(r);
        return true;
    }

private:
    bool mysql_begin() // 开启事务
    {
        if (mysql_query(&mysql_con, "begin") != 0)
            return false;

        return true;
    }
    bool mysql_commit() // 提交事物
    {
        if (mysql_query(&mysql_con, "commit") != 0)
            return false;

        return true;
    }
    bool mysql_rollback() // 回滚
    {
        if (mysql_query(&mysql_con, "rollback") != 0)
            return false;

        return true;
    }

private:
    MYSQL mysql_con;
    string db_ips;
    string db_username;
    string db_dbname;
    string db_passwd;
};

class socket_listen // 监听套接字的处理
{
private:
    std::string m_ips;
    short m_port;
    struct event_base *base;
    struct evconnlistener *listener;

public:
    socket_listen(const std::string &ips, short port) : m_ips(ips), m_port(port), base(nullptr), listener(nullptr) {}

    // 设置event_base
    void Set_base(struct event_base *base);

    // 获取event_base
    struct event_base *Get_base() const;

    // 获取lfd
    int Get_sockfd() const;

    struct evconnlistener *Get_listener() const { return listener; }

    // 接受客户端连接的回调函数
    static void accept_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *address, int socklen, void *ctx);

    ~socket_listen();
};

class socket_con
{ // 处理连接套接字
public:
    socket_con(struct bufferevent *bev);
    ~socket_con()
    {
        if (bev)
            bufferevent_free(bev);
    }

    static void read_cb(struct bufferevent *bev, void *ctx);
    static void write_cb(struct bufferevent *bev, void *ctx);
    static void event_cb(struct bufferevent *bev, short events, void *ctx);
    static void Send_err(struct bufferevent *bev);
    static void Send_ok(struct bufferevent *bev);
    static void User_Register(struct bufferevent *bev, const Json::Value &val);
    static void User_Login(struct bufferevent *bev, const Json::Value &val);
    static void User_Show_ticket(struct bufferevent *bev, const Json::Value &val);
    static void User_Subscrib_ticket(struct bufferevent *bev, const Json::Value &val);
    static void User_Show_Sub_ticket(struct bufferevent *bev, const Json::Value &val);
    static void User_Cancel_ticket(struct bufferevent *bev, const Json::Value &val);

private:
    struct bufferevent *bev;
};

void socket_listen::Set_base(struct event_base *base)
{
    this->base = base;

    // 初始化监听器
    struct sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(m_port);
    inet_pton(AF_INET, m_ips.c_str(), &sin.sin_addr);

    listener = evconnlistener_new_bind(base, accept_cb, base,
                                       LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
                                       LIS_MAX, (struct sockaddr *)&sin, sizeof(sin));

    if (!listener)
    {
        cerr << "Failed to create listener!" << endl;
        exit(1);
    }
}

struct event_base *socket_listen::Get_base() const
{
    return base;
}

int socket_listen::Get_sockfd() const
{
    if (listener)
    {
        return evconnlistener_get_fd(listener);
    }
    return -1;
}

void socket_listen::accept_cb(struct evconnlistener *listener,
                              evutil_socket_t fd,
                              struct sockaddr *address,
                              int socklen,
                              void *ctx)
{

    cout << "New client connected! Client socket fd: " << fd << endl;

    struct event_base *base = (struct event_base *)ctx;

    struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);

    bufferevent_setcb(bev, socket_con::read_cb, NULL /*socket_con::write_cb*/, socket_con::event_cb, nullptr);

    bufferevent_enable(bev, EV_READ);
}

socket_listen::~socket_listen()
{
    if (listener)
    {
        evconnlistener_free(listener);
    }
}

void socket_con::Send_err(struct bufferevent *bev)
{
    Json::Value ERR_val;
    ERR_val["status"] = "Error";
    string err_response = ERR_val.toStyledString();
    int n = bufferevent_write(bev, err_response.c_str(), err_response.size());
    if (n != 0)
    {
        cout << "Send_err error!" << endl;
    }
    return;
}

void socket_con::Send_ok(struct bufferevent *bev)
{
    Json::Value OK_val;
    OK_val["status"] = "OK";
    string ok_response = OK_val.toStyledString();
    int n = bufferevent_write(bev, ok_response.c_str(), ok_response.size());
    if (n != 0)
    {
        cout << "Send_ok error!" << endl;
    }
    return;
}

void socket_con::User_Register(struct bufferevent *bev, const Json::Value &val)
{
    string tel = val["user_tel"].asString();
    string passwd = val["user_passwd"].asString();
    string username = val["user_name"].asString();

    //bufferevent_write(bev,username.c_str(),username.size());

    if (tel.empty() || passwd.empty() || username.empty())
    {
        Send_err(bev); // 调用 Send_err 发送错误信息
        return;
    }
    mysql_client db_client;
    if (!db_client.mysql_ConnectServer())
    {
        Send_err(bev);
        return;
    }
    if (!db_client.mysql_Register(tel, passwd, username))
    {
        Send_err(bev); // 调用 Send_err 发送错误信息
        return;
    }

    Send_ok(bev);
}

void socket_con::User_Login(struct bufferevent *bev, const Json::Value &val)
{
    string tel = val["user_tel"].asString();
    string passwd = val["user_passwd"].asString();
    string user_name;

    mysql_client cli;
    if (!cli.mysql_ConnectServer())
    {
        Send_err(bev);
        cout << "mysql_ConnectServer()error" << endl;
        return;
    }
    if (!cli.mysql_Login(tel, passwd, user_name))
    {
        Send_err(bev);
        cout << "mysql_Login() error" << endl;
        return;
    }

    Json::Value res_val;
    res_val["status"] = "OK";
    res_val["user_name"] = user_name;//user_name
    int n = bufferevent_write(bev, res_val.toStyledString().c_str(), res_val.toStyledString().size());
    if (n != 0)
    {
        cout << "res_val send error" << endl;
    }
}

void socket_con::User_Show_ticket(struct bufferevent *bev, const Json::Value &val)
{
    mysql_client cli;
    if (!cli.mysql_ConnectServer())
    {
        Send_err(bev);
        cout << "mysql_ConnectServer()error" << endl;
        return;
    }
    Json::Value resval;
    if (!cli.mysql_Show_ticket(resval))
    {
        Send_err(bev); // 查询失败时发送错误信息
        cout << "mysql_Show_ticket() error" << endl;
        return;
    }
    string response = resval.toStyledString();
    int n_sent = bufferevent_write(bev, response.c_str(), response.size());
}

void socket_con::User_Subscrib_ticket(struct bufferevent *bev, const Json::Value &val)
{
    int tk_id = val["index"].asInt();
    string tel = val["tel"].asString();

    mysql_client cli;
    if (!cli.mysql_ConnectServer())
    {
        Send_err(bev);
        cout << "mysql_ConnectServer()error" << endl;
        return;
    }

    if (!cli.mysql_Subscribe_ticket(tk_id, tel))
    {
        Send_err(bev);
        return;
    }

    Send_ok(bev);
    return;
}

void socket_con::User_Show_Sub_ticket(struct bufferevent *bev, const Json::Value &val)
{

    // 从客户端请求中提取用户的电话号码
    string tel = val["tel"].asString();

    // 创建 MySQL 客户端连接
    mysql_client cli;
    if (!cli.mysql_ConnectServer()) // 尝试连接 MySQL 服务器
    {
        Send_err(bev); // 发送错误响应
        cerr << "mysql_ConnectServer() error: Failed to connect to the database." << endl;
        return;
    }

    Json::Value resval;

    // 查询用户预约信息
    bool query_result = cli.mysql_User_Show(resval, tel);
    if (!query_result)
    {
        cerr << "mysql_User_Show() error: Failed to retrieve user ticket data for " << tel << endl;
        Send_err(bev); // 查询失败时发送错误信息
        return;
    }

    // 发送查询结果到客户端
    string response = resval.toStyledString();
    int n = bufferevent_write(bev, response.c_str(), response.size());
    if (n < 0)
    {
        cerr << "bufferevent_write error: Failed to send response data." << endl;
        return;
    }

    cout << "Sent ticket information for user: " << tel << endl;
    return;
}

void socket_con::User_Cancel_ticket(struct bufferevent *bev, const Json::Value &val)
{
    int yd_id = val["yd_id"].asInt();
    int tk_id = val["tk_id"].asInt();
    mysql_client cli;
    if (!cli.mysql_ConnectServer()) // 尝试连接 MySQL 服务器
    {
        Send_err(bev); // 发送错误响应
        cerr << "mysql_ConnectServer() error: Failed to connect to the database." << endl;
        return;
    }
    if (!cli.User_Cancel_ticket(yd_id, tk_id))
    {
        Send_err(bev);
        return;
    }
    Send_ok(bev);
    return;
}

void socket_con::read_cb(struct bufferevent *bev, void *ctx)
{
    char buffer[256] = {0};
    int n = bufferevent_read(bev, buffer, sizeof(buffer) - 1); // 确保不会越界
    if (n > 0)
    {
        // 打印接收到的数据
        // cout << "Client fd: " << bufferevent_getfd(bev) << " recv data: " << buffer << endl;

        Json::Value val;
        Json::Reader Read;
        if (!Read.parse(buffer, val))
        {
            cout << "Recv_data:解析json失败" << endl;
            Send_err(bev);
            return;
        }
        int op_type = val["type"].asInt();
        switch (op_type)
        {
        case Enter:
            User_Login(bev, val);
            val.clear();
            break;
        case Register:
            User_Register(bev, val);
            val.clear();
            break;
        case Check:
            User_Show_ticket(bev, val);
            val.clear();
            break;
        case Schedule:
            User_Subscrib_ticket(bev, val);
            break;
        case Mine:
            User_Show_Sub_ticket(bev, val);
            break;
        case Cancel:
            User_Cancel_ticket(bev, val);
            break;
        case Leave:
            break;
        default:
            cout << "输入无效" << endl;
            break;
        }
    }
    else if (n == 0)
    {
        cout << "Client fd: " << bufferevent_getfd(bev) << "closed" << endl;

        bufferevent_free(bev);
    }
    else if (n < 0)
    {
        cout << "read_cb error" << endl;
    }
}

void socket_con::event_cb(struct bufferevent *bev, short events, void *ctx)
{
    // 获取客户端fd
    evutil_socket_t fd = bufferevent_getfd(bev);

    if (events & BEV_EVENT_EOF)
    {
        std::cout << "Client fd " << fd << " closed the connection." << endl;
    }
    // 释放 bufferevent 资源
    bufferevent_free(bev);
    delete (socket_con *)ctx;
}

int main()
{

    struct event_base *base = event_base_new();
    if (!base)
    {
        cerr << "event_base_new error" << endl;
        return 1;
    }

    socket_listen listener("127.0.0.1", 8080);
    listener.Set_base(base);

    event_base_dispatch(base);

    event_base_free(base);

    return 0;
}